﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
using System.IO;
using System.Collections;

namespace 开挖量计算
{
    public partial class Form1 : Form
    {
        AcadApplication AcadApp;
        AcadDocument AcadDoc;

        public Form1()
        {
            InitializeComponent();
        }

        private void 启动CAD()
        {
            try
            {
                AcadApp =
               (AcadApplication)System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Application");
                AcadDoc = AcadApp.ActiveDocument;
            }
            catch
            {
                OpenFileDialog pOpenDG = new OpenFileDialog();
                pOpenDG.Filter = "CAD文件(*.dwg)|*.dwg|CAD图形文件(*.dxf)|*.dxf";
                pOpenDG.Title = "打开CAD文件";
                pOpenDG.ShowDialog();
                string filePath = pOpenDG.FileName;
                if (filePath == "")
                {
                    MessageBox.Show("选择CAD文件无效！", "文件无效！");
                    Application.Exit();
                }
                AcadApp = new AcadApplication();
                AcadDoc = AcadApp.Documents.Open(filePath, null, null);
            }
            AcadApp.Application.Visible = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            启动CAD();
            刷新图层显示();
        }

        private void 计算开挖量_Click(object sender, EventArgs e)
        {
            Microsoft.VisualBasic.Interaction.AppActivate(AcadApp.Caption);
            AcadSelectionSet mySelectionSet;
            mySelectionSet = AcadDoc.SelectionSets.Add("NewSelectionSet01");
            Int16[] FilterType = new Int16[1];
            object[] FilterData = new object[1];
            FilterType[0] = 0;
            FilterData[0] = "3DFACE";
            mySelectionSet.SelectOnScreen(FilterType, FilterData);
            double[] triVCds = new double[12];//三角形顶点坐标数组
            double calHeight = Double.Parse(CalHeightTextBox.Text), allW = 0, allT = 0;
            foreach (AcadObject triObject in mySelectionSet)
            {
                Acad3DFace triFace = (Acad3DFace)triObject;
                triVCds = (double[])triFace.Coordinates;
                SortArray(triVCds, out triVCds);
                if (calHeight <= triVCds[8])//全部为开挖方量
                {
                    double sABC;
                    sABC = ((triVCds[3] - triVCds[0]) * (triVCds[7] - triVCds[1]) - (triVCds[4] -
                   triVCds[1]) * (triVCds[6] - triVCds[0])) / 2;
                    sABC = Math.Abs(sABC);
                    allW += sABC * (triVCds[8] - calHeight) + (triVCds[2] + triVCds[5] - 2 * triVCds[8])
                   * sABC / 3;
                }
                else if (calHeight >= triVCds[2])//全部为填方
                {
                    double sABC;
                    sABC = ((triVCds[3] - triVCds[0]) * (triVCds[7] - triVCds[1]) - (triVCds[4] -
                   triVCds[1]) * (triVCds[6] - triVCds[0])) / 2;
                    sABC = Math.Abs(sABC);
                    allT += sABC * (calHeight - triVCds[2]) / 2 + sABC * (2 * triVCds[2] - triVCds[5]
                   - triVCds[8]) / 3;
                }
                else//既有挖方也有填方
                {
                    double d1, d2;
                    d2 = triVCds[7] - (calHeight - triVCds[8]) * (triVCds[2] - triVCds[8]) / (triVCds[7]
                   - triVCds[1]);
                    d1 = (triVCds[6] - triVCds[0]) * (d2 - triVCds[1]) / (triVCds[7] - triVCds[1])
                   + triVCds[0];
                    double sADB, sCDB;
                    sADB = ((triVCds[3] - triVCds[0]) * (d2 - triVCds[1]) - (triVCds[4] - triVCds[1])
                   * (d1 - triVCds[0])) / 2;
                    sADB = Math.Abs(sADB);
                    sCDB = ((triVCds[3] - triVCds[6]) * (d2 - triVCds[7]) - (triVCds[4] - triVCds[7])
                   * (d1 - triVCds[6])) / 2;
                    sCDB = Math.Abs(sCDB);
                    if (calHeight >= triVCds[5])
                    {
                        double tempValue, V1;
                        tempValue = (triVCds[2] - calHeight) / (triVCds[2] - triVCds[5]);
                        V1 = tempValue * tempValue * sADB * (triVCds[2] - calHeight) / 3;
                        allW += V1;
                        allT += ((2 * triVCds[2] - triVCds[5] - triVCds[8]) / 3 - triVCds[2] + calHeight)
                       * (sADB + sCDB) + V1;
                    }
                    else
                    {
                        double tempValue, V2;
                        tempValue = (calHeight - triVCds[8]) / (triVCds[5] - triVCds[2]);
                        V2 = tempValue * tempValue * sCDB * (calHeight - triVCds[8]) / 3;
                        allT += V2;
                        allW += (sADB + sCDB) * (calHeight - triVCds[8]) - V2;
                    }
                }
            }
            MessageBox.Show("计算开挖总方量为：" + allW.ToString() + "\n" + "计算填方总方量为：" +
           allT.ToString());
            AcadDoc.SelectionSets.Item("NewSelectionSet01").Delete();
        }

        private void SortArray(double[] arrayIn, out double[] arrayOut)
        {
            arrayOut = new double[9];
            int No1 = 1, No2 = 2, No3 = 3;
            if (arrayIn[2] < arrayIn[5])
            {
                if (arrayIn[5] < arrayIn[8])
                {
                    No1 = 3;
                    No2 = 2;
                    No3 = 1;
                }
                else
                {
                    No1 = 2;
                    if (arrayIn[2] < arrayIn[8])
                    {
                        No2 = 3;
                        No3 = 1;
                    }
                    else
                    {
                        No2 = 1;
                        No3 = 3;
                    }
                }
            }
            else
            {
                if (arrayIn[2] < arrayIn[8])
                {
                    No1 = 3;
                    No2 = 1;
                    No3 = 2;
                }
                else
                {
                    No1 = 1;
                    if (arrayIn[5] < arrayIn[8])
                    {
                        No2 = 3;
                        No3 = 2;
                    }
                    else
                    {
                        No2 = 2;
                        No3 = 3;
                    }
                }
            }
            arrayOut[0] = arrayIn[3 * No1 - 3];
            arrayOut[1] = arrayIn[3 * No1 - 2];
            arrayOut[2] = arrayIn[3 * No1 - 1];
            arrayOut[3] = arrayIn[3 * No2 - 3];
            arrayOut[4] = arrayIn[3 * No2 - 2];
            arrayOut[5] = arrayIn[3 * No2 - 1];
            arrayOut[6] = arrayIn[3 * No3 - 3];
            arrayOut[7] = arrayIn[3 * No3 - 2];
            arrayOut[8] = arrayIn[3 * No3 - 1];
        }

        private void 刷新图层显示()
        {
            layerComboBox.Items.Clear();
            int i;
            for (i = 0; i < AcadDoc.Layers.Count; i++)
            {
                layerComboBox.Items.Add(AcadDoc.Layers.Item(i).Name.ToString());
            }
            layerComboBox.Text = AcadDoc.ActiveLayer.Name.ToString();
        }

        private void 非平场开挖计算_Click(object sender, EventArgs e)
        {
            Microsoft.VisualBasic.Interaction.AppActivate(AcadApp.Caption);
            AcadSelectionSet mySelectionSet, mySelectionSet02;
            mySelectionSet = AcadDoc.SelectionSets.Add("NewSelectionSet02");
            mySelectionSet02 = AcadDoc.SelectionSets.Add("NewSelectionSet03");
            Int16[] FilterType = new Int16[1];
            object[] FilterData = new object[1];
            FilterType[0] = 0;
            FilterData[0] = "3DFACE";
            mySelectionSet.SelectOnScreen(FilterType, FilterData);//选择DEM01 
            Int16[] FilterType2 = new Int16[2];
            object[] FilterData2 = new object[2];
            FilterType2[0] = 0;
            FilterData2[0] = "3DFACE";
            FilterType2[1] = 8;
            FilterData2[1] = layerComboBox.Text;
            double[] point1 = new double[3];
            point1[0] = 0; point1[1] = 0; point1[2] = 0;
            mySelectionSet02.Select(AcSelect.acSelectionSetAll, point1, point1, FilterType2,
FilterData2);//选择DEM02 
            double minHeight = ((double[])((Acad3DFace)mySelectionSet.Item(0)).Coordinates)[2];
            double[] dem01VCds = new double[12], dem02VCds = new double[12];//三角形顶点坐标数组
            foreach (AcadObject triObject in mySelectionSet)
            {
                Acad3DFace triFace = (Acad3DFace)triObject;
                dem01VCds = (double[])triFace.Coordinates;
                double min = GetMinValue(dem01VCds[2], dem01VCds[5], dem01VCds[8]);
                if (minHeight > min)
                {
                    minHeight = min;
                }
            }
            foreach (AcadObject triObject in mySelectionSet02)
            {
                Acad3DFace triFace = (Acad3DFace)triObject;
                dem02VCds = (double[])triFace.Coordinates;
                double min = GetMinValue(dem02VCds[2], dem02VCds[5], dem02VCds[8]);
                if (minHeight > min)
                {
                    minHeight = min;
                }
            }
            double allW01 = 0, allW02 = 0, allW;
            foreach (AcadObject triObject in mySelectionSet)
            {
                Acad3DFace triFace = (Acad3DFace)triObject;
                dem01VCds = (double[])triFace.Coordinates;
                SortArray(dem01VCds, out dem01VCds);
                if (minHeight <= dem01VCds[8])//全部为开挖方量
                {
                    double sABC;
                    sABC = ((dem01VCds[3] - dem01VCds[0]) * (dem01VCds[7] - dem01VCds[1]) -
                   (dem01VCds[4] - dem01VCds[1]) * (dem01VCds[6] - dem01VCds[0])) / 2;
                    sABC = Math.Abs(sABC);
                    allW01 += sABC * (dem01VCds[8] - minHeight) + (dem01VCds[2] + dem01VCds[5] - 2
                   * dem01VCds[8]) * sABC / 3;
                }
            }
            foreach (AcadObject triObject in mySelectionSet02)
            {
                Acad3DFace triFace = (Acad3DFace)triObject;
                dem02VCds = (double[])triFace.Coordinates;
                SortArray(dem02VCds, out dem02VCds);
                if (minHeight <= dem02VCds[8])//全部为开挖方量
                {
                    double sABC;
                    sABC = ((dem02VCds[3] - dem02VCds[0]) * (dem02VCds[7] - dem02VCds[1]) -
                   (dem02VCds[4] - dem02VCds[1]) * (dem02VCds[6] - dem02VCds[0])) / 2;
                    sABC = Math.Abs(sABC);
                    allW02 += sABC * (dem02VCds[8] - minHeight) + (dem02VCds[2] + dem02VCds[5] - 2
                   * dem02VCds[8]) * sABC / 3;
                }
            }
            allW = allW01 - allW02;
            if (allW > 0)
            {
                MessageBox.Show("计算总开挖方量为：" + allW.ToString());
                richTextBox1.Text = "挖填前与挖填后DEM最低高程为：" + minHeight.ToString() + "\n计算总开挖方量为：" + allW.ToString(); 
            }
            else
            {
                allW = -allW;
                MessageBox.Show("计算总填方量为：" + allW.ToString());
                richTextBox1.Text = "挖填前与挖填后DEM最低高程为：" + minHeight.ToString() + "\n计算总填方量为：" + allW.ToString(); 
            }
            AcadDoc.SelectionSets.Item("NewSelectionSet02").Delete();
            AcadDoc.SelectionSets.Item("NewSelectionSet03").Delete();
        }

        private double GetMinValue(double number01, double number02, double number03)
        {
            double min = number01;
            if (min > number02)
            {
                min = number02;
            }
            if (min > number03)
            {
                min = number03;
            }
            return min;
        }
    }
}
